﻿using CleanArchitecture.Core.Helper;
using CleanArchitecture.Core.Interfaces.Cache;
using CleanArchitecture.Infrastructure.AutoMapper;
using CleanArchitecture.Infrastructure.Configuration;
using CleanArchitecture.Infrastructure.Entities;
using CleanArchitecture.Infrastructure.Entities.System.DataDic;
using CleanArchitecture.Infrastructure.Entities.SystemModules;
using CleanArchitecture.Infrastructure.Interfaces.SystemManage;
using CleanArchitecture.Infrastructure.Models;
using CleanArchitecture.Infrastructure.Models.SystemManage;
using System;
using System.Collections.Generic;
using System.Linq;

namespace CleanArchitecture.Web.Factories
{
    public class SystemManageModelFactory : ISystemManageModelFactory
    {
        private readonly ISystemDataDicService _systemdatadicService;
        private readonly ISystemModuleService _systemmoduleService;
        private readonly ICacheManager _cacheManager;
        public SystemManageModelFactory(ISystemDataDicService systemdatadicService,
            ISystemModuleService systemmoduleService,
            ICacheManager cacheManager)
        {
            this._systemdatadicService = systemdatadicService;
            this._systemmoduleService = systemmoduleService;
            this._cacheManager = cacheManager;
        }

        public IList<SystemDataDicTree> GetSystemDataDicTreesByGroupType(EntityEnumConfig.DataDicGroup grouptype)
        {
            var key = string.Format(DefaultCacheConfig.SystemDataDicTreeCacheKeyByGroup, grouptype.ToString());
            var datadictrees = _cacheManager.Get(key, () =>
            {
                return _systemdatadicService.GetDataDicTreeByGroupType(grouptype);
            });
            return datadictrees;
        }
        public IList<SystemDataDicTreeNodeModel> PrepareSystemDataDicTreeNodes(int grouptype)
        {
            EntityEnumConfig.DataDicGroup egrptype = (EntityEnumConfig.DataDicGroup)CommonHelper.To(grouptype, grouptype.GetType());
            var datadictrees = GetSystemDataDicTreesByGroupType(egrptype);
            return PopulateSystemDataDicTreeNodeModel(datadictrees.Where(t => t.ParentId == 0).ToList(), datadictrees);
        }

        private IList<SystemDataDicTreeNodeModel> PopulateSystemDataDicTreeNodeModel(IList<SystemDataDicTree> iterators, IList<SystemDataDicTree> menuRecords)
        {
            if (iterators == null || iterators.Count <= 0)
                return null;

            var nodes = new List<SystemDataDicTreeNodeModel>();
            IList<SystemDataDicTreeNodeModel> childrens = null;
            foreach (var record in iterators.OrderBy(r => r.DisplayOrder))
            {
                var menu = new SystemDataDicTreeNodeModel()
                {
                    id = record.Id,
                    pid = record.ParentId,
                    grouptype = (int)record.GroupType,
                    datatype = (int)(record.DataType.HasValue ? record.DataType.Value : 0),
                    title = record.DisplayName,
                    name = record.DisplayName,
                    value = record.Id.IdEncode(),
                    displayorder = record.DisplayOrder
                };
                if (menuRecords.Any(m => m.ParentId == record.Id))
                {
                    menu.spread = true;
                    childrens = PopulateSystemDataDicTreeNodeModel(menuRecords.Where(r => r.ParentId.Equals(record.Id)).ToList(), menuRecords);
                    if (childrens != null)
                        menu.children = menu.children.Concat(childrens).ToList();
                }
                else menu.spread = false;
                nodes.Add(menu);
            }
            return nodes;
        }

        /// <summary>
        /// Prepare paged news item list model
        /// </summary>
        /// <param name="searchModel">News item search model</param>
        /// <returns>News item list model</returns>
        public virtual SystemDataDicButtonListModel PrepareSystemDataDicButtonListModel(SystemDataDicTreeSearchModel searchModel)
        {
            //get system module buttons
            if (searchModel.GroupType != EntityEnumConfig.DataDicGroup.ModuleButton) return null;
            var buttonItems = _systemdatadicService.GetSystemDataDicButtons(searchModel.Id, searchModel.Page - 1, searchModel.PageSize);

            //prepare list model
            var models = new SystemDataDicButtonListModel().PrepareToGrid(buttonItems, () =>
            {
                return buttonItems.Select(button =>
                {
                    //fill in model values from the entity
                    var buttonItemModel = button.ToModel<SystemDataDicButtonModel>();
                    return buttonItemModel;
                });
            });
            return models;
        }

        public IList<SystemModuleTreeNodeModel> PrepareSystemModuleTreeNodes()
        {
            var moduleNodes = _systemmoduleService.GetSystemMenusAll();
            return PopulateSystemModuleTreeNodeModel(moduleNodes.Where(m => m.ModuleType == EntityEnumConfig.SysModuleType.Root).ToList(), moduleNodes);
        }
        //Same as AdminUserModelFactory.PopulateMenu
        private IList<SystemModuleTreeNodeModel> PopulateSystemModuleTreeNodeModel(IList<SystemModule> iterators, IList<SystemModule> menuRecords)
        {
            if (iterators == null || iterators.Count <= 0)
                return null;

            var nodes = new List<SystemModuleTreeNodeModel>();
            IList<SystemModuleTreeNodeModel> childrens = null;
            foreach (var record in iterators)
            {
                var menu = new SystemModuleTreeNodeModel()
                {
                    id = record.Id,
                    pid = record.ParentId,
                    moduletype = (int)record.ModuleType,
                    title = record.DisplayName,
                    href = (record.OpenOnNewWindow == EntityEnumConfig.YesorNo.YES
                        && record.ModuleType == EntityEnumConfig.SysModuleType.ModulePage
                        && !string.IsNullOrEmpty(record.UrlRoute))
                         ? record.UrlRoute : string.Empty,
                    disabled = false
                };
                if (record.ParentId == 0 && record.ModuleType == EntityEnumConfig.SysModuleType.Root)
                    menu.disabled = true;
                if (record.ModuleType == EntityEnumConfig.SysModuleType.ModulePage)
                {
                    menu.spread = false;
                    menu.children = null;
                }
                else
                {
                    menu.spread = true;
                    childrens = PopulateSystemModuleTreeNodeModel(menuRecords.Where(r => r.ParentId.Equals(record.Id)).ToList(), menuRecords);
                    if (childrens != null)
                        menu.children = menu.children.Concat(childrens).ToList();
                }
                nodes.Add(menu);
            }
            return nodes;
        }
        public IList<SystemModuleModel> GetSystemModuleModelsById(int id)
        {
            var moduleNodes = _systemmoduleService.GetSystemMenusAll();
            Func<SystemModule, SystemModuleModel> SelectModuleModel = (entity) =>
             {
                 var moduleModel = entity.ToModel<SystemModuleModel>();
                 if (moduleModel.ModuleAssignedButtons != null && moduleModel.ModuleAssignedButtons.Count > 0)
                     moduleModel.ModuleAssignedButtonNames = GetSystemModuleDispatchedButtonName(moduleModel.ModuleAssignedButtons.ToArray());
                 return moduleModel;
             };

            if (id == 0 || (moduleNodes.FirstOrDefault(m => m.ModuleType == EntityEnumConfig.SysModuleType.Root)?.Id ?? 0) == id) //根节点全部返回
                return moduleNodes.Select(entity => SelectModuleModel.Invoke(entity)).ToList();
            else
            {
                var node = moduleNodes.FirstOrDefault(m => m.Id == id);
                if (node != null)
                {
                    if (node.ModuleType == EntityEnumConfig.SysModuleType.ModulePage) //系统模块返回本身节点
                        return moduleNodes.Where(m => m.Id == id)
                                          .Select(entity => SelectModuleModel.Invoke(entity))
                                          .ToList();
                    else  //否则导航节点返回自身及其下所有子节点
                        return moduleNodes.Where(m => m.Id == id || m.ParentId == id)
                                          .Select(entity => SelectModuleModel.Invoke(entity))
                                          .ToList();
                }
                else return null;
            }            
        }
        /// <summary>
        /// 根据分配给系统模块的Ids 存储在sys_module的ModuleButtonIds 关联sys_datadic表的Id
        /// </summary>
        /// <param name="datadicBtnIds"></param>
        /// <returns></returns>
        private string GetSystemModuleDispatchedButtonName(int[] datadicBtnIds)
        {
            var buttons = _systemdatadicService.GetSystemDataDicButtonsByIds(datadicBtnIds);
            if (buttons.Count == 0) return string.Empty;
            return string.Join(", ", buttons.Select(b => b.DisplayName).ToArray());
        }

        public SystemModuleModel GetSystemModuleModelById(int id)
        {
            var entity = _systemmoduleService.GetSystemModuleById(id);
            if (entity == null) return null;
            var model = entity.ToModel<SystemModuleModel>();
            if (entity.ParentId == 0) model.ParentIdDisplay = entity.DisplayName;
            else
            {
                var parent = _systemmoduleService.GetSystemModuleById(entity.ParentId);
                model.ParentIdDisplay = parent.DisplayName;
            }
            return model;
        }
    }
}
